
package es.upm.dit.gsi.opactv.searchengines;

import es.upm.dit.gsi.opactv.util.Connection;
import es.upm.dit.gsi.opactv.util.FormatData;
import es.upm.dit.gsi.opactv.Book;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class CAM implements SearchEngine {

    private Connection conn = new Connection();
    private FormatData fd = new FormatData();
    private String url, author, title, tags;

    public CAM() {
        // COLLECTION!
    }

    public void set(String title, String author, String tags) {
        this.title = title;
        this.author = author;
        this.tags = tags;
    }

    public ArrayList<Book> getBooks() {
        ArrayList<Book> books = new ArrayList();
        getURL();
        String list = getList();
        if (list.indexOf("info_error")!=-1) return books;
        String workArea = fd.format(list, "border06", "breakWord");
        int index;
        while ((index = workArea.indexOf("<table"))!=-1) {
            String container = fd.format(workArea, "<table", "</table>");
            String itemContainer = fd.format(container, "<td>", "</td>");
            String item = fd.format(itemContainer, ">", "<");
            String bookTitle="", bookAuthor="";
            StringTokenizer st = new StringTokenizer(item, "/");
            while (st.hasMoreTokens()) {
                String token = decode(st.nextToken().trim());
                if (st.hasMoreTokens()) {
                    if (!bookTitle.equals("")) bookTitle += "/";
                    bookTitle += token;
                } else bookAuthor = token;
            }
            if (!isBlacklisted(bookAuthor)) {
                int indexAuthor = bookAuthor.indexOf(";");
                if (indexAuthor!=-1) {
                    bookAuthor = bookAuthor.substring(0, indexAuthor).trim();
                }
                if (bookAuthor.indexOf(author)!=-1) {
                    Book book = new Book(bookTitle, fixAuthor(bookAuthor));
                    book.addOptional("CAM:HASH", hash(item));
                    books.add(book);
                }
            }
            workArea = workArea.substring(index+1);
        }
        return books;
    }

    public void completeBook(Book book) {
        String list, hash = book.getOptional("CAM:HASH");
        int countOut = 0;
        do {
            getURL();
            list = getList();
            countOut++;
        } while(list.indexOf("info_error")!=-1 && countOut<10);
        if (!list.equals("")) {
            String workArea = fd.format(list, "border06", "breakWord");
            int index;
            while ((index = workArea.indexOf("<table"))!=-1) {
                String container = fd.format(workArea, "<table", "</table>");
                String itemContainer = fd.format(container, "<td>", "</td>");
                String itemID = fd.format(itemContainer, "AbnOpacDoc(", ");");
                String item = fd.format(itemContainer, ">", "<");
                if (hash(item).equals(hash)) {
                    for (String tag : getTags(itemID)) book.addTag(tag);
                    break;
                }
                workArea = workArea.substring(index+1);
            }
        }
    }

    private String fixAuthor(String thisAuthor) {
        int index = thisAuthor.indexOf("(");
        if (index!=-1) thisAuthor = thisAuthor.substring(0, index).trim();
        return thisAuthor;
    }

    private ArrayList<String> getTags(String itemID) {
        ArrayList<String> allTags = new ArrayList();
        String params = "ACC=165&DOC=" + itemID + "&xshist=1&xsfmtd=4567776";
        String response = conn.post(url, params);
        String tagsContainer = fd.format(response, "Materias", "</tr>");
        int index;
        while ((index=tagsContainer.indexOf("<div>"))!=-1) {
            String tag = fd.format(tagsContainer, "<div>", "</div>");
            allTags.add(fd.format(tag, ">", "<"));
            tagsContainer = tagsContainer.substring(index+1);
        }
        return allTags;
    }

    private String getList() {
        String response = "";
        try {
            String params = "ACC=131&subcat=%2F&xssort=4579848&xsnlis=100&select03=02";
            if (title!=null) params += "&xsqf12=" + urlEncoder(title);
            if (author!=null) params += "&xsqf03=" + urlEncoder(author);
            if (tags!=null) params += "&xsqf05=" + urlEncoder(tags);
            response = conn.post(url, params);
        } catch(Exception ex) {
            //System.err.println(ex);
        } finally {
            return response;
        }
    }

    private void getURL() {
        String urlBase = "http://www.madrid.org/biblio_catalogos/cgi-bin/abnetopac";
        String response = conn.get(urlBase);
        url = "http://www.madrid.org" + fd.format(response, "URL=", "?");
    }

    private boolean isBlacklisted(String data) {
        String[] blacklist = {"version","adapted","basado","adaptacion",
                              "edicion","produced","retold","rewritten",
                              "simplified","VHS","DVD","guion","directed"};
        data = cleanAccents(data);
        for (int i=0; i<blacklist.length; i++) {
            if (data.toLowerCase().indexOf(blacklist[i])!=-1) return true;
        }
        return false;
    }

    private String cleanAccents(String data) {
        data = data.replaceAll("á", "a");
        data = data.replaceAll("é", "e");
        data = data.replaceAll("í", "i");
        data = data.replaceAll("ó", "o");
        data = data.replaceAll("ú", "u");
        return data;
    }

    private String decode(String data) {
        data = data.replaceAll("&nbsp;", " ");
        return data;
    }

    private String urlEncoder(String params) {
        String encoded = "";
        try {
            encoded = URLEncoder.encode(params, "UTF-8");
        } catch (Exception ex) {
            // System.err.println(ex);
        } finally {
            return encoded;
        }
    }

    private String hash(String data) {
        String hash = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(data.getBytes(), 0, data.length());
            hash = new BigInteger(1, md.digest()).toString(16);
            while (hash.length()<32) hash = "0" + hash;
        } catch(Exception ex) {
            //System.err.println(ex);
        } finally {
            return hash;
        }
    }

}
